#pragma once
#include <iostream>
#include <sys/epoll.h>
#include <string>
#include <memory>
#include <unordered_map>
#include <vector>
#include "Logger.hpp"
#include "Connection.hpp"
#include "Epoller.hpp"
#include <unistd.h>

class Reactor
{
    static const uint32_t default_epoll_events = EPOLLIN | EPOLLET;//设置为边缘触发ET模式

public:
    Reactor():_epoll(std::make_unique<Epoller>())
    {}

    void EnableReadWrite(int sockfd,bool rflag,bool wflag)
    {
        uint32_t event = EPOLLET;
        if(rflag)
            event |= EPOLLIN;
        if(wflag)
            event |= EPOLLOUT;
        _epoll->Mod(sockfd,event);
    }
    void AddConnection(const std::shared_ptr<Connection>& conn)
    {
        //判断是否已经存在
        if(_hash.count(conn->SockFd()) > 0)
            return;
        conn->SetOwner(this);
        _hash.insert({conn->SockFd(),conn});
        _epoll->Add(conn->SockFd(),default_epoll_events);
        LOG(LogLevel::INFO) << "AddConnection sucess";
    }
    void DelConnection(int fd)
    {
        if(_hash.count(fd) > 0)
        {
            _hash.erase(fd);
            _epoll->Del(fd);
            close(fd);
        }
    }
    void Dispatcher(int nfds)
    {
        auto& queue = _epoll->GetQueue();
        for(int i = 0;i < nfds;i++)
        {
            int fd = queue[i].data.fd;
            uint32_t event = queue[i].events;
            
            if(event & EPOLLHUP)
                event |= EPOLLIN;
            if(event & EPOLLERR)
                event |= EPOLLIN;
            //判断存在性非常必要：增加代码的鲁棒性
            if(_hash.count(fd) && event & EPOLLIN)
                _hash[fd]->Read();
            //判断存在非常必要：增加代码的鲁棒性
            if(_hash.count(fd) && (_hash[fd]->GetW() || event & EPOLLOUT))
                _hash[fd]->Write();
        }
    }
    void Run()
    {
        while(true)
        {
            int nfds = _epoll->Wait();
            // std::cout << nfds << std::endl;
            Dispatcher(nfds);
            // CheckTimeOut();
        }
    }
    ~Reactor()
    {}
    
public:
    std::unordered_map<int,std::shared_ptr<Connection>> _hash;
    std::unique_ptr<Epoller> _epoll;//不想使用epoll的原生接口，做一层封装
};